package com.hcy.app.screen.cipher

import android.util.Base64
import java.security.*
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec
import javax.crypto.Cipher


/**
 * RSA算法计算相对较慢,不适合处理大量数据，需要结合实际场景使用。
 * 数据加密场景下：发送方使用公钥加密，接收方使用私钥解密，不适合大量传输数据，性能很慢；
 * 数字签名场景下：发送方使用私钥签名，接收方使用公钥验签，数字签名本身并不会直接对数据本身加密，只是验证发送者身份，不存在性能问题。
 */
object CryptUtilsForRsa {
    private const val RSA_ALGORITHM = "RSA"
    private const val TRANSFORMATION = "RSA/ECB/PKCS1Padding"
    private const val KEY_SIZE = 2048  // 推荐使用2048位密钥[2,7](@ref)

    // 加密分段大小 (2048位密钥：245字节)[3,6](@ref)
    private const val ENCRYPT_BLOCK_SIZE = 245

    // 解密分段大小 (2048位密钥：256字节)[3](@ref)
    private const val DECRYPT_BLOCK_SIZE = 256

    /**
    * 生成RSA密钥对
    * @return Pair(公钥Base64, 私钥Base64)
    */
    fun generate(): Pair<String, String> {
        val keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM)
        keyPairGenerator.initialize(KEY_SIZE, SecureRandom())
        val keyPair = keyPairGenerator.generateKeyPair()

        val publicKey = Base64.encodeToString(
            keyPair.public.encoded,
            Base64.NO_WRAP
        )

        val privateKey = Base64.encodeToString(
            keyPair.private.encoded,
            Base64.NO_WRAP
        )

        return Pair(publicKey, privateKey)
    }

    /**
    * 公钥加密
    * @param data 明文数据
    * @param publicKeyBase64 Base64编码的公钥
    */
    fun encrypt(data: String, publicKeyBase64: String): String {
        val publicKey = restorePublicKey(publicKeyBase64)
        val cipher = Cipher.getInstance(TRANSFORMATION)
        cipher.init(Cipher.ENCRYPT_MODE, publicKey)

        val dataBytes = data.toByteArray(Charsets.UTF_8)
        val encryptedBytes = processByBlocks(
            dataBytes,
            cipher,
            ENCRYPT_BLOCK_SIZE
        )

        return Base64.encodeToString(encryptedBytes, Base64.NO_WRAP)
    }

    /**
    * 私钥解密
    * @param encryptedDataBase64 Base64编码的密文
    * @param privateKeyBase64 Base64编码的私钥
    */
    fun decrypt(encryptedDataBase64: String, privateKeyBase64: String): String {
        val privateKey = restorePrivateKey(privateKeyBase64)
        val cipher = Cipher.getInstance(TRANSFORMATION)
        cipher.init(Cipher.DECRYPT_MODE, privateKey)

        val encryptedBytes = Base64.decode(encryptedDataBase64, Base64.NO_WRAP)
        val decryptedBytes = processByBlocks(
            encryptedBytes,
            cipher,
            DECRYPT_BLOCK_SIZE
        )

        return String(decryptedBytes, Charsets.UTF_8)
    }

    // 恢复公钥对象
    private fun restorePublicKey(publicKeyBase64: String): PublicKey {
        val keyBytes = Base64.decode(publicKeyBase64, Base64.NO_WRAP)
        val keySpec = X509EncodedKeySpec(keyBytes)
        return KeyFactory.getInstance(RSA_ALGORITHM)
            .generatePublic(keySpec)
    }

    // 恢复私钥对象
    private fun restorePrivateKey(privateKeyBase64: String): PrivateKey {
        val keyBytes = Base64.decode(privateKeyBase64, Base64.NO_WRAP)
        val keySpec = PKCS8EncodedKeySpec(keyBytes)
        return KeyFactory.getInstance(RSA_ALGORITHM)
            .generatePrivate(keySpec)
    }

    // 分段处理数据
    private fun processByBlocks(
        data: ByteArray,
        cipher: Cipher,
        blockSize: Int
    ): ByteArray {
        val output = ArrayList<Byte>()
        var offset = 0

        while (offset < data.size) {
            val chunkSize = minOf(blockSize, data.size - offset)
            val chunk = data.copyOfRange(offset, offset + chunkSize)
            output.addAll(cipher.doFinal(chunk).toList())
            offset += chunkSize
        }

        return output.toByteArray()
    }

}